#include "ScriptSystem.h"
#include "../ECS/Components/ScriptComponent.h"
#include "../ECS/Entity.h"
#include <entt/entt.hpp>
#include "Log.h"

namespace SCION_CORE::Systems
{
  ScriptSystem::ScriptSystem(SCION_CORE::ECS::Registry &registry)
      : m_Registry(registry), m_bMainLoaded{false}
  {
  }
  bool ScriptSystem::LoadMainCript(sol::state &lua)
  {
    try
    {
      auto result = lua.safe_script_file("./assets/scripts/main.lua");
    }
    catch (const sol::error &err)
    {
      SCION_ERROR("Failed to load main.lua script: " + std::string(err.what()));
      return false;
    }

    sol::table main_lua = lua["main"];
    sol::optional<sol::table> bUpdateExists = main_lua[1];
    if (!bUpdateExists)
    {
      SCION_ERROR("main.lua does not contain a valid 'main' table with update function.");
      return false;
    }

    sol::table update_script = main_lua[1];
    sol::function update = update_script["update"];
    sol::optional<sol::table> bRenderExists = main_lua[2];
    if (bRenderExists == sol::nullopt)
    {
      SCION_ERROR("main.lua does not contain a valid 'main' table with render function.");
      return false;
    }
    sol::table render_script = main_lua[2];
    sol::function render = render_script["render"];

    SCION_CORE::ECS::Entity mainLuaScript{m_Registry, "main_script", ""};
    mainLuaScript.AddComponent<SCION_CORE::ECS::ScriptComponent>(
        SCION_CORE::ECS::ScriptComponent{
            update,
            render});

    m_bMainLoaded = true;
    SCION_INFO("Successfully loaded and executed main.lua script.");
    return true;
  }

  void ScriptSystem::Update()
  {
    if (!m_bMainLoaded)
    {
      SCION_ERROR("Main script not loaded. Skipping script update.");
      return;
    }

    auto view = m_Registry.GetRegistry().view<SCION_CORE::ECS::ScriptComponent>();
    for (const auto &entity : view)
    {
      SCION_CORE::ECS::Entity ent{m_Registry, entity};
      if (ent.GetName() == "main_script")
      {
        continue;
      }
      auto &script = ent.GetComponent<SCION_CORE::ECS::ScriptComponent>();
      auto error = script.update(entity);
      if (!error.valid())
      {
        sol::error err = error;
        SCION_ERROR("Error during script update: " + std::string(err.what()));
      }
    }
  }

  void ScriptSystem::Render()
  {
    if (!m_bMainLoaded)
    {
      SCION_ERROR("Main script not loaded. Skipping script render.");
      return;
    }

    auto view = m_Registry.GetRegistry().view<SCION_CORE::ECS::ScriptComponent>();
    for (const auto &entity : view)
    {
      SCION_CORE::ECS::Entity ent{m_Registry, entity};
      if (ent.GetName() == "main_script")
      {
        continue;
      }
      auto &script = ent.GetComponent<SCION_CORE::ECS::ScriptComponent>();
      auto error = script.render(entity);
      if (!error.valid())
      {
        sol::error err = error;
        SCION_ERROR("Error during script render: " + std::string(err.what()));
      }
    }
  }
}